package com.zc.im.seqsvr.handler.error;

import com.zc.im.common.exception.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.reactive.error.DefaultErrorAttributes;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.*;
import reactor.core.publisher.Mono;

import java.util.Map;

import static org.springframework.boot.web.error.ErrorAttributeOptions.Include.*;

/**
 * Project：im
 * Date：2022/4/14
 * Time：9:59
 * Description：全局异常处理
 *
 * @author Challen.Zhang
 * @version 1.0
 */
@Component
@Order(-2)
@Slf4j
public class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {

    private static final String ERROR_ATTRIBUTE = DefaultErrorAttributes.class.getName() + ".ERROR";


    public GlobalErrorWebExceptionHandler(ErrorAttributes errorAttributes,
                                          WebProperties webProperties,
                                          //基类未初始化
                                          ServerCodecConfigurer serverCodecConfigurer,
                                          ApplicationContext applicationContext) {
        super(errorAttributes, webProperties.getResources(), applicationContext);
        this.setMessageWriters(serverCodecConfigurer.getWriters());
    }

    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(final ErrorAttributes errorAttributes) {
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
    }

    private Mono<ServerResponse> renderErrorResponse(final ServerRequest request) {
        Object obj = request.exchange().getAttribute(ERROR_ATTRIBUTE);
        final Map<String, Object> errorPropertiesMap = getErrorAttributes(request, ErrorAttributeOptions.of(
                //STACK_TRACE,
                MESSAGE,
                EXCEPTION, BINDING_ERRORS
        ));
        errorPropertiesMap.remove("message");
        if (obj instanceof CustomException) {
            CustomException exception = (CustomException) obj;
            errorPropertiesMap.put("status", exception.getResultEnum().getStatus());
            errorPropertiesMap.put("error", exception.getResultEnum().getMessage());
            if (exception.getMessage() != null) {
                errorPropertiesMap.put("error", exception.getMessage());
            }
            errorPropertiesMap.put("success",false);
        }

        log.error("url : [{}] , status : [{}] , exception : ", errorPropertiesMap.get("path"), errorPropertiesMap.get("status"), (Exception) obj);
        return ServerResponse.status(HttpStatus.OK)
                .contentType(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(errorPropertiesMap));
    }
}